import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:pointycastle/export.dart';
import 'package:convert/convert.dart';


// --------------- KeyPair ---------------
class KeyPair {
  final String privateKey;
  final String publicKey;

  KeyPair({required this.privateKey, required this.publicKey});
}

/// ECIES 加密工具类（secp256k1 + AES-CTR + HMAC-SHA256）
class ECIESUtil {
  // ----------------- 公钥加密 -----------------
  static Uint8List encrypt(String plaintext, String publicKeyHex) {
    // 1. 准备明文数据
    final plaintextBytes = Uint8List.fromList(plaintext.codeUnits);

    // 2. 解码公钥（04开头未压缩格式）
    final publicKeyBytes = hex.decode(publicKeyHex);
    final curve = ECCurve_secp256k1();
    final publicKeyPoint = curve.curve.decodePoint(publicKeyBytes)!;

    // 3. 生成临时密钥对
    final ephemeralKeyPair = _generateEphemeralKeyPair();
    final ephemeralPrivateKey = _hexToBigInt(ephemeralKeyPair.privateKey);

    // 4. ECDH 计算共享密钥
    final sharedSecretPoint = publicKeyPoint * ephemeralPrivateKey;
    final sharedSecretBytes = sharedSecretPoint!.x!.toBigInteger()!.toRadixString(16).padLeft(64, '0');
    final sharedSecret = hex.decode(sharedSecretBytes);

    // 5. 派生密钥（SHA-256哈希）
    final aesKey = _sha256(Uint8List.fromList([...sharedSecret, ...utf8.encode('AES_KEY')]));
    final hmacKey = _sha256(Uint8List.fromList([...sharedSecret, ...utf8.encode('HMAC_KEY')]));

    // 6. AES-CTR 加密
    final aesCipher = CTRStreamCipher(AESEngine())
      ..init(true, ParametersWithIV(KeyParameter(aesKey), Uint8List(16)));
    final ciphertext = aesCipher.process(plaintextBytes);

    // 7. HMAC 计算
    final hmac = HMac(SHA256Digest(), 32)
      ..init(KeyParameter(hmacKey));
    hmac.update(ciphertext, 0, ciphertext.length);
    final hmacDigest = Uint8List(32);
    hmac.doFinal(hmacDigest, 0);

    // 8. 组合结果：临时公钥(65) + 密文 + HMAC(32)
    final ephemeralPublicKeyBytes = hex.decode(ephemeralKeyPair.publicKey);
    return Uint8List.fromList([...ephemeralPublicKeyBytes, ...ciphertext, ...hmacDigest]);
  }

  // ----------------- 私钥解密 -----------------
  static String decrypt(Uint8List encryptedData, String privateKeyHex) {
    // 1. 分解数据
    final ephemeralPublicKeyBytes = encryptedData.sublist(0, 65);
    final ciphertext = encryptedData.sublist(65, encryptedData.length - 32);
    final receivedHmac = encryptedData.sublist(encryptedData.length - 32);

    // 2. 解码临时公钥
    final curve = ECCurve_secp256k1();
    final ephemeralPublicKey = curve.curve.decodePoint(ephemeralPublicKeyBytes)!;

    // 3. 计算共享密钥
    final privateKey = _hexToBigInt(privateKeyHex);
    final sharedSecretPoint = ephemeralPublicKey * privateKey;
    final sharedSecretBytes = sharedSecretPoint!.x!.toBigInteger()!.toRadixString(16).padLeft(64, '0');
    final sharedSecret = hex.decode(sharedSecretBytes);

    // 4. 派生密钥（与加密一致）
    final aesKey = _sha256(Uint8List.fromList([...sharedSecret, ...utf8.encode('AES_KEY')]));
    final hmacKey = _sha256(Uint8List.fromList([...sharedSecret, ...utf8.encode('HMAC_KEY')]));

    // 5. 验证 HMAC
    final hmac = HMac(SHA256Digest(), 32)
      ..init(KeyParameter(hmacKey));
    hmac.update(ciphertext, 0, ciphertext.length);
    final calculatedHmac = Uint8List(32);
    hmac.doFinal(calculatedHmac, 0);
    if (!_constantTimeEquals(receivedHmac, calculatedHmac)) {
      throw Exception('HMAC 验证失败');
    }

    // 6. AES 解密
    final aesCipher = CTRStreamCipher(AESEngine())
      ..init(false, ParametersWithIV(KeyParameter(aesKey), Uint8List(16)));
    return String.fromCharCodes(aesCipher.process(ciphertext));
  }

  // --------------- 工具方法 ---------------
  static KeyPair _generateEphemeralKeyPair() {
    final curve = ECCurve_secp256k1();
    final n = curve.n!;
    BigInt d;
    do {
      d = _generatePrivateKey(n);
    } while (d <= BigInt.zero);
    final Q = curve.G * d;
    return KeyPair(
      privateKey: _bigIntToHex(d),
      publicKey: hex.encode(Q!.getEncoded(false)),
    );
  }

  static BigInt _generatePrivateKey(BigInt n) {
    final rand = Random.secure();
    final bytes = Uint8List(32);
    for (int i = 0; i < bytes.length; i++) {
      bytes[i] = rand.nextInt(256);
    }
    return _bytesToBigInt(bytes) % n;
  }

  static Uint8List _sha256(Uint8List data) {
    final digest = SHA256Digest();
    return digest.process(data);
  }

  static bool _constantTimeEquals(Uint8List a, Uint8List b) {
    if (a.length != b.length) return false;
    int result = 0;
    for (int i = 0; i < a.length; i++) {
      result |= a[i] ^ b[i];
    }
    return result == 0;
  }

  static BigInt _hexToBigInt(String hexStr) => BigInt.parse(hexStr, radix: 16);
  static String _bigIntToHex(BigInt number) => number.toRadixString(16).padLeft(64, '0');
  static Uint8List _bigIntToBytes(BigInt number) {
    // 将 List<int> 显式转换为 Uint8List
    return Uint8List.fromList(hex.decode(_bigIntToHex(number)));
  }
  static BigInt _bytesToBigInt(Uint8List bytes) => _hexToBigInt(hex.encode(bytes));
}

// ----------------- 测试用例 -----------------
void main() {
  // 密钥对
  // const privateKey = 'dc47e339eaf56c9bd0e3ab8f9e4c28cacd0433e94b57e485da1b0d129682355d';
  // const publicKey = '047ed82bdfdc76451ab319b507aa9e7365c1230d43ecf62da7504ad45499e61a4733426585b611e7e31a7ee2abd379b245b2a2221fea6340f3899ba46266a547c7';

  const privateKey = 'cea0a58cd03873f6e0139da975cd2970b0de4688ca3811dcab6f6e025439ce94';
  const publicKey = '0407fddbb0d09cd962ef963cf7c835aa8183c4102dfbb03c75e9325f91223441f756025ab50a63f6da6c008dc54d9e8a9cbe6ac103210fb64251ea7213e12fc05d';

  // 测试加密/解密
  const originalText = 'c2dc45a848b6e330327fcbe98a93e3121cbfb0726a5131ba63b733e2b439ef76';
  print('原始文本: $originalText');

  final encrypted = ECIESUtil.encrypt(originalText, publicKey);
  print('加密结果: ${hex.encode(encrypted)}');
  print('加密结果长度: ${encrypted.length} 字节');

  final decrypted = ECIESUtil.decrypt(encrypted, privateKey);
  print('解密结果: $decrypted');

  assert(decrypted == originalText, '验证失败');
  print('测试通过 ✅');
}